package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"demo1/coze/token"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"time"
)

const (
	// 请求凭证，从访问控制申请
	AccessKeyID     = "AKLTOWZkNjZlNDhiZDcxNDdlNmJjYjk3NDU4OTBiMDJlMTg"
	SecretAccessKey = "TVRObVpqZzROamRqWWpBd05ESmpOemxsTldSbE0ySmpZelk0WVdZMU1EZw=="

	// 请求地址
	Addr = "https://rtc.volcengineapi.com"
	Path = "/" // 路径，不包含 Query

	// 请求接口信息
	Service = "rtc"
	Region  = "cn-beijing"
	Action  = "StartVoiceChat"
	Version = "2024-12-01"
)

type Req struct {
	RoomId string `json:"roomId"`
	Uid    string `json:"uid"`
	TaskId string `json:"taskId"`
}

func hmacSHA256(key []byte, content string) []byte {
	mac := hmac.New(sha256.New, key)
	mac.Write([]byte(content))
	return mac.Sum(nil)
}

func getSignedKey(secretKey, date, region, service string) []byte {
	kDate := hmacSHA256([]byte(secretKey), date)
	kRegion := hmacSHA256(kDate, region)
	kService := hmacSHA256(kRegion, service)
	kSigning := hmacSHA256(kService, "request")

	return kSigning
}

func hashSHA256(data []byte) []byte {
	hash := sha256.New()
	if _, err := hash.Write(data); err != nil {
		log.Printf("input hash err:%s", err.Error())
	}

	return hash.Sum(nil)
}

func InitToken(c *gin.Context) {
	var req Req
	c.ShouldBindJSON(&req)
	var (
		appID  = "67e1223e01d405017e93a8d0"
		appKey = "c419eaceac9d4d44b8f36968f1196a49"
		roomID = req.RoomId
		userID = req.Uid
	)
	tokens := token.New(appID, appKey, roomID, userID)
	tokens.ExpireTime(time.Now().Add(time.Hour * 2))
	tokens.AddPrivilege(token.PrivSubscribeStream, time.Time{})
	tokens.AddPrivilege(token.PrivPublishStream, time.Now().Add(time.Minute))

	s, err := tokens.Serialize()
	if err != nil {
		panic(err)
	}
	c.JSON(http.StatusOK, gin.H{
		"data": s,
	})
}

func doRequest(method string, queries url.Values, body []byte) (error, int, string) {
	requestAddr := fmt.Sprintf("%s%s?%s", Addr, Path, queries.Encode())
	log.Printf("request addr: %s\n", requestAddr)

	request, err := http.NewRequest(method, requestAddr, bytes.NewBuffer(body))
	if err != nil {
		return fmt.Errorf("bad request: %w", err), 500, ""
	}

	// 2. 构建签名材料
	now := time.Now()
	date := now.UTC().Format("20060102T150405Z")
	authDate := date[:8]
	request.Header.Set("X-Date", date)

	payload := hex.EncodeToString(hashSHA256(body))
	request.Header.Set("X-Content-Sha256", payload)
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	queryString := strings.Replace(queries.Encode(), "+", "%20", -1)
	signedHeaders := []string{"host", "x-date", "x-content-sha256", "content-type"}
	var headerList []string
	for _, header := range signedHeaders {
		if header == "host" {
			headerList = append(headerList, header+":"+request.Host)
		} else {
			v := request.Header.Get(header)
			headerList = append(headerList, header+":"+strings.TrimSpace(v))
		}
	}
	headerString := strings.Join(headerList, "\n")

	canonicalString := strings.Join([]string{
		method,
		Path,
		queryString,
		headerString + "\n",
		strings.Join(signedHeaders, ";"),
		payload,
	}, "\n")
	log.Printf("canonical string:\n%s\n", canonicalString)

	hashedCanonicalString := hex.EncodeToString(hashSHA256([]byte(canonicalString)))
	log.Printf("hashed canonical string: %s\n", hashedCanonicalString)

	credentialScope := authDate + "/" + Region + "/" + Service + "/request"
	signString := strings.Join([]string{
		"HMAC-SHA256",
		date,
		credentialScope,
		hashedCanonicalString,
	}, "\n")
	log.Printf("sign string:\n%s\n", signString)

	// 3. 构建认证请求头
	signedKey := getSignedKey(SecretAccessKey, authDate, Region, Service)
	signature := hex.EncodeToString(hmacSHA256(signedKey, signString))
	log.Printf("signature: %s\n", signature)

	authorization := "HMAC-SHA256" +
		" Credential=" + AccessKeyID + "/" + credentialScope +
		", SignedHeaders=" + strings.Join(signedHeaders, ";") +
		", Signature=" + signature
	request.Header.Set("Authorization", authorization)
	log.Printf("authorization: %s\n", authorization)

	// 4. 打印请求，发起请求
	requestRaw, err := httputil.DumpRequest(request, true)
	if err != nil {
		return fmt.Errorf("dump request err: %w", err), 500, err.Error()
	}

	log.Printf("request:\n%s\n", string(requestRaw))

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		return fmt.Errorf("do request err: %w", err), 500, err.Error()
	}

	// 5. 打印响应
	responseRaw, err := httputil.DumpResponse(response, true)
	if err != nil {
		return fmt.Errorf("dump response err: %w", err), 500, err.Error()
	}

	log.Printf("response:\n%s\n", string(responseRaw))
	defer response.Body.Close()
	if response.StatusCode == 200 {
		log.Printf("请求成功")
	} else {
		log.Printf("请求失败")
	}
	all, err := io.ReadAll(response.Body)
	return nil, response.StatusCode, string(all)
}

func main() {
	r := gin.Default()
	r.POST("startVoiceChat", StartVoiceChat)
	r.POST("startSubtitle", StartSubtitle)
	r.POST("initToken", InitToken)

	r.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "无此页面",
		})
	})

	r.Run(":8999")
}

func StartVoiceChat(c *gin.Context) {

	var req Req
	err := c.BindJSON(&req)

	jsonStr := `{
	"AppId": "67e1223e01d405017e93a8d0",
	"TaskId": "",
	"RoomId": "",
	"Config": {
		"AsrConfig": {
			"Provider": "volcano",
			"ProviderParams": {
				"Mode": "bigmodel",
				"AppId": "8775346635",
				"AccessToken": "W9Yn9B_xmV-Gwfq460G09JvN4MxqZzVJ"
			}
		},
		"TTSConfig": {
			"Provider": "volcano_bidirection",
			"ProviderParams": {
				"App": {
					"appid": "8775346635",
					"token": "W9Yn9B_xmV-Gwfq460G09JvN4MxqZzVJ"
				},
				"audio": {
					"voice_type": "zh_female_linjianvhai_moon_bigtts"
				},
				"ResourceId": "volc.service_type.10029"
			}
		},
		"LLMConfig": {
			"Mode": "CozeBot",
			"BotId": "7475242805384921114",
			"Url": "https://api.coze.cn",
			"APIKey": "pat_ghIg9ETblUlskN2yyTPZ9tZcXuNMUXu3dRKsh9xuNBRAT4m2PxkWRZ5L7jghFjUT",
			"UserId": "123",
			"CozeBotConfig": {
				"Url": "https://api.coze.cn",
				"BotId": "7475242805384921114",
				"APIKey": "pat_ghIg9ETblUlskN2yyTPZ9tZcXuNMUXu3dRKsh9xuNBRAT4m2PxkWRZ5L7jghFjUT",
				"UserId": "123"
			}
		},
		"SubtitleConfig": {
			"DisableRTSSubtitle": false,
			"ServerMessageUrl": "https://dev-ait-api.91medicine.net/huixuanjiao/mi-app/api/coze/subtitlemsg",
		    "ServerMessageSignature": "11111111",
			"SubtitleMode": 1
		}
	},
	"AgentConfig": {
		"TargetUserId": [
			"222"
		],
		"WelcomeMessage": "你好，我是宁波医保智能助理，我叫“宁保儿”，有任何医保方面的问题都可以问我。",
		"UserId": "robot_user"
	}
}`

	// 将JSON字符串解析为map
	var data map[string]interface{}
	err = json.Unmarshal([]byte(jsonStr), &data)
	if err != nil {
		log.Fatalf("Error unmarshaling JSON: %v", err)
	}

	data["TaskId"] = req.TaskId
	data["RoomId"] = req.RoomId
	data["AgentConfig"].(map[string]interface{})["TargetUserId"] = []interface{}{req.Uid}

	//body := []byte(jsonStr)

	updatedJsonBytes, err := json.Marshal(data)
	// GET 请求例子
	query1 := make(url.Values)
	// 1. 构建请求
	query1.Set("Action", Action)
	query1.Set("Version", Version)
	err, code, response := doRequest(http.MethodPost, query1, updatedJsonBytes)

	var result map[string]interface{}
	err = json.Unmarshal([]byte(response), &result)
	c.JSON(http.StatusOK, gin.H{
		"code":   code,
		"result": result,
	})
}

func StartSubtitle(c *gin.Context) {
	var req Req
	err := c.ShouldBindJSON(&req)
	if err != nil {
		return
	}

	jsonStr := `{
    "AppId": "67e1223e01d405017e93a8d0",
    "RoomId": "Room1",
    "TaskId": "Task1",
    "LanguageConfig": {
        "SourceLanguages": [
            {
                "UserId": "user1",
                "LanguageCode": [
                    "zh"
                ]
            }
        ]
    },
    "DistributionMode": 1,
    "ServerMessage": {
        "Signature": "TestSignature",
        "Url": "https://dev-ait-api.91medicine.net/huixuanjiao/mi-app/api/coze/subtitlemsg"
    },
    "ReceiverList": []
}`
	// 将JSON字符串解析为map
	var data map[string]interface{}
	err = json.Unmarshal([]byte(jsonStr), &data)
	if err != nil {
		log.Fatalf("Error unmarshaling JSON: %v", err)
	}

	data["RoomId"] = req.RoomId
	data["LanguageConfig"].(map[string]interface{})["SourceLanguages"].([]interface{})[0].(map[string]interface{})["UserId"] = req.Uid

	updatedJsonBytes, err := json.Marshal(data)
	//body := []byte(jsonStr)
	// GET 请求例子
	query1 := make(url.Values)
	query1.Set("Action", "StartSubtitle")
	query1.Set("Version", "2024-06-01")
	err, code, response := doRequest(http.MethodPost, query1, updatedJsonBytes)

	var result map[string]interface{}
	err = json.Unmarshal([]byte(response), &result)
	c.JSON(http.StatusOK, gin.H{
		"code":   code,
		"result": result,
	})

}
